<!--发帖表单-->
<script setup>
import {ElementUtils} from "@/assets/js/ElementUtils";
import {PostUtils} from "@/assets/js/PostUtils";
import {setupMapGetters, setupMapState} from "@/assets/js/vuexUtils";
import {routeNames} from "@/router";
import {PostApi} from "@ginstone/nga-api/dist/src/method/PostApi";
import {PostParam} from "@ginstone/nga-api/dist/src/params/PostParams";
import {nextTick, onMounted, onUnmounted, ref, toRefs} from "vue";
import {useRoute, useRouter} from "vue-router";
import {useStore} from "vuex";
import PostTextArea from "@/components/post/PostTextArea.vue";
import PostDropdown from "@/components/post/PostDropdown.vue";
import EmoteDialog from "@/components/common/dialog/EmoteDialog.vue";
import PostBbsCodeButtons from "@/components/post/PostBbsCodeButtons.vue";
import {Hidden} from "@ginstone/nga-api/dist/src/enums/Hidden";
import {routeNameIn} from "@/assets/js/routerUtils";
import {KeyPressListener} from "@ginstone/common-utils/dist/src/utils/KeyPressListener";
import {PostAction} from "@ginstone/nga-api/dist/src/enums/PostAction";
import {ReadApi} from "@ginstone/nga-api/dist/src/method/ReadApi";
import {NukeApi} from "@ginstone/nga-api/dist/src/method/NukeApi";
import {UploadParam} from "@ginstone/nga-api/dist/src/params/UploadParam";
import {formatDate} from "@ginstone/common-utils/dist/src/utils/DateUtils";
import Attachment from "@/components/post/attachment/Attachment.vue";
import {UploadFilled} from "@element-plus/icons-vue";
import {WatermarkPosition} from "@ginstone/nga-api/dist/src/enums/WatermarkPosition";
import NgaCollapse from "@/components/content/bbscode/NgaCollapse.vue";
import TopKeyDropdown from "@/components/post/TopKeyDropdown.vue";

const props = defineProps({
  // PostAction 类型
  action: {type: String},
  // 参数
  params: {type: Object},
  // 简单模式，只显示文本框
  simple: {type: Boolean},
})

const getClient = setupMapGetters("Account", ["getClient"]).getClient.value
const {action, params} = toRefs(props)
const store = useStore();
const {currentUid} = setupMapState("Account", ['currentUid']);
const {fontColor} = setupMapState("Resources", ['fontColor']);
const {fontSize} = setupMapState("Resources", ['fontSize']);
const {fonts} = setupMapState("Resources", ['fonts']);
const {cache} = setupMapState("Read", ['cache']);
const router = useRouter();
const route = useRoute();

const emit = defineEmits(['prepare-error', 'send-error'])


// 正式发送参数 start
// 标题
const post_subject = ref();
// 正文
const post_content = ref();
// 附件列表
const attachs = ref([]);
// (编辑) 超时编辑添加内容到最后
const modify_append = ref();
// 隐藏发布
const hidden = ref();
// 匿名发布
const anony = ref();
// 正式发送参数 end

//正在提交回复
const sending = ref(false);
//水印位置
const position = ref();

// 版面id
const forumId = ref();
const tid = ref();
const pid = ref();
// 上传用校验码
const auth = ref();
// 已有附件
const attachments = ref([]);
const closeDialog = () => store.commit("Dialog/closeDialog", 'post-form')
// 准备参数
let prepareParams;
// 编辑器
const editor = ref();
// 发送准备请求
const prepare = () => {
  const loading = ElementUtils.loading({target: "#post-form",});
  prepareParams = PostUtils.buildPrepareParams(action.value, params.value)
  PostApi.prepare(getClient(), prepareParams).then(res => {
    console.log(res)

    // 判断编辑是否超时
    if (res.modifyAppend) {
      modify_append.value = 1
    } else {
      // 向编辑器中插入预设内容
      editor.value.insertText(res.content || res.contentOriginal)
    }

    attachments.value = res.attachments;
    tid.value = res.topicId
    pid.value = res.replyId || 0

    forumId.value = res.forumId;
    post_subject.value = res.title

    hidden.value = res.hidden ? Hidden.HIDDEN : Hidden.CANCEL;
    auth.value = res.auth;

  }).catch(reason => {
    // 发送异常, 报错, 关闭弹窗
    ElementUtils.exceptionHandler(reason)
    emit('prepare-error', reason);
    closeDialog();
  }).finally(() => {
    loading.close();
  })
}
const showDialog = (name) => store.commit("Dialog/showDialog", {name,})
// 保存
const save = () => {
  // 发布参数
  const postParam = new PostParam(post_subject.value, post_content.value, attachs.value, modify_append.value, hidden.value, anony.value);
  return PostApi.send(getClient(), prepareParams, postParam).catch(ElementUtils.exceptionHandler)
}
// 发布并跳转
const send = () => {
  if (sending.value) {
    return;
  }
  sending.value = true;
  ElementUtils.notice({message: "正在提交回复..."})
  // 发布参数
  save().then(res => {
    const {location} = res;
    closeDialog();
    if (route.name === routeNames.post.modify) {
      // 编辑完成
      ReadApi.toReply(getClient(), location.replyId || 0).then(loc => {
        console.log(loc)
        cache.value.remove({tid: loc.topicId, page: loc.page.toString()})
        router.push({name: routeNames.read.topic, params: {id: loc.topicId}, query: {page: loc.page, account: currentUid.value}, hash: "#P" + loc.replyId})
      })
    } else {
      // 发帖、回复完成
      cache.value.clear()
      router.push({name: routeNames.read.topic, params: {id: location.topicId}, query: {page: 'e', account: currentUid.value}, hash: "#P" + (location.replyId || 0)})
    }
  }).catch(ElementUtils.exceptionHandler).finally(() => {
    sending.value = false;
  })
}
// 处理下拉列表选中事件
const handleCommand = ({code, param}) => {
  if (param) {
    editor.value.bracket(`[${code}=${param}]`, `[/${code}]`)
  } else {
    editor.value.bracket(`[${code}]`, `[/${code}]`)
  }
}
// 添加文本
const insertText = (text) => {
  editor.value.insertText(text)
}
// 移除已有附件回调
const onDeleted = (array, index) => {
  const {view} = array.splice(index, 1)[0]
  //  删除所有被使用的代码
  view.bbsCodes.forEach(item => editor.value.replace(item.code, ''))
}
// 匿名警告
const beforeAnony = () => {
  const text = "匿名发布的内容如果违反版规将会>>加 重 处 罚<<"
  const title = "匿名警告";
  if (route.name === routeNames.post.new) {
    //发新帖
    return ElementUtils.confirm("匿名发布主题需要5000铜币\n" + text, title).then(() => true).catch(() => false)
  }
  if (route.name === routeNames.post.reply || route.name === routeNames.post.quote) {
    //   回复或引用
    return ElementUtils.confirm("匿名发布回复需要100铜币\n" + text, title).then(() => true).catch(() => false)
  }
  return new Promise(r => r(true));
}
const keyListener = new KeyPressListener([
  {
    name: "发布回复",
    event: {code: "Enter", ctrlKey: true,}, method: () => {
      send()
    },
  },
], undefined, false);
// 插入bbsCode
const insertBbsCode = (bbsCode, filename) => {
  // 检查文件名是否符合pixiv 或 twitter格式
  let text = "";

  let matched = false;
  {
    const matcher = /(\d+)_p(\d{1,3})/.exec(filename);
    if (matcher) {
      text = `pix:${matcher[1]}\n`;
      matched = true
    }
  }
  {
    const matcher = /(\d{19})/.exec(filename);
    if (matcher) {
      text = `https://x.com/i/status/${matcher[1]}\n`
      // insertText(`twi:${matcher[1]}\n`)
      matched = true
    }
  }

  text += bbsCode

  if (matched) {
    text = `[quote]\n${text}\n[/quote]\n`
  }

  insertText(text)
}
const onPastedFile = (files) => {
  // console.log(files)

  queueUpload(files, undefined, ({view}) => {
    // 粘贴上传成功后直接插入预设bbsCode到正文中
    insertBbsCode(view.bbsCodes[view.bbsCodes.length - 1].code, view.filename)
  })
}
//按顺序上传多个文件
const queueUpload = async (files, position, callback) => {
  if (files.length > 1) {
    ElementUtils.notice({message: "多个文件将按顺序上传"})
  } else {
    ElementUtils.notice({message: "正在上传..."})
  }
  for (let uploadFile of files) {
    const res = await upload(uploadFile)

    if (callback && res) {
      callback(res)
    }
  }
  ElementUtils.notice({message: "文件上传完毕"})
}
const dialogShow = ref(false)
//上传文件
const upload = (file, position) => {
  const uploadText = "upload at " + formatDate(new Date(), 'yyyy_MM_dd_hh_mm')
  const param = new UploadParam(auth.value, forumId.value, uploadText, file, position)
  console.log(param)
  return NukeApi.attachUpload('/upload', param).then(res => {
    // 添加到附件列表
    attachs.value.push(res)
    console.log(res)
    return res;
  }).catch(ElementUtils.exceptionHandler)
}

const accept = [".png", ".jpg", ".jpeg", ".gif", ".zip", ".mp3", ".mp4"]

const uploadRequest = ({file}) => {
  return upload(file, position.value)
}

onMounted(() => {
  window.addEventListener("keyup", keyListener.listener, false)
  nextTick(() => {
    setTimeout(() => prepare(), 100)
  })
});
onUnmounted(() => {
  window.removeEventListener("keyup", keyListener.listener)
})

</script>

<template>
  <div id="post-form">
    <!--    header-->
    <div>
      <div v-if="action===PostAction.QUOTE" style="color:red">引用功能有更高的卡审风险, 不建议使用</div>
      <!--      标签按钮-->
      <div v-if="!simple" id="code-button">
        <!--字体-->
        <post-dropdown class="post-dropdown" title="字体" @command="handleCommand">
          <el-dropdown-item v-for="({label,value}) in fonts" :command="{code:'font',param:value}">
            <span :style="{fontFamily:value}">{{ label }}</span>
          </el-dropdown-item>
        </post-dropdown>
        <!--字体颜色-->
        <post-dropdown class="post-dropdown" title="颜色" @command="handleCommand">
          <el-dropdown-item v-for="value in fontColor" :command="{code:'color',param:value}" :style="{backgroundColor:value,}">
            <span v-for="i in 8">&nbsp;</span>
          </el-dropdown-item>
        </post-dropdown>
        <!--字体大小-->
        <post-dropdown class="post-dropdown" title="大小" @command="handleCommand">
          <el-dropdown-item v-for="({label,value}) in fontSize" :command="{code:'size',param:value}">
            {{ label }}
          </el-dropdown-item>
        </post-dropdown>
        <!--表情-->
        <el-tag class="post-dropdown clickable" size="small" @click="showDialog('emote')">表情</el-tag>
        <!--其他代码-->
        <post-bbs-code-buttons @command="handleCommand"/>
      </div>
      <!--超时提示-->
      <div v-if="modify_append">帖子超过修改时限，在此提交的内容将被增加至原帖末尾, 如需修改原帖请联系版主</div>
      <!--隐藏和匿名-->
      <div>
        <el-switch v-model="hidden" :active-value="Hidden.HIDDEN" :inactive-value="Hidden.CANCEL" active-text="隐藏" style="margin-right: 5px"/>
        <el-switch v-if="routeNameIn($route,routeNames.post.quote,routeNames.post.reply,routeNames.post.new)" v-model="anony" :active-value="1" :beforeChange="beforeAnony"
                   :inactive-value="undefined" active-text="匿名"/>
      </div>
      <!--标题-->
      <div>
        <el-input v-model="post_subject" placeholder="标题">
          <template #prepend>
            <top-key-dropdown :forum-id="forumId" @command="post_subject=!post_subject?$event:($event+post_subject)"/>
          </template>
        </el-input>
      </div>
    </div>
    <!--正文文本框-->
    <div>
      <post-text-area ref="editor" v-model="post_content" @pasted-file="onPastedFile"/>
    </div>
    <!--    footer-->
    <footer>
      <el-button type="success" @click="send">发布(Ctrl+Enter)</el-button>
      <el-button type="primary" @click="dialogShow=true">上传</el-button>
    </footer>
    <!--    附件列表-->
    <el-row>
      <el-col v-if="attachments && attachments.length>0" :span="12">
        <!--显示已有的附件列表-->
        <h4>已有附件</h4>
        <template v-for="({view},index) in attachments">
          <attachment :data="view" :index="index" :pid="pid" :tid="tid" with-editor @delete="onDeleted(attachments,index)"
                      @insert="insertBbsCode"/>
        </template>
      </el-col>
      <el-col v-if="attachs && attachs.length>0" :span="12">
        <!--本次上传附件列表-->
        <h4>本次上传附件</h4>
        <template v-for="({view},index) in attachs">
          <attachment :data="view" :index="index" :pid="pid" :tid="tid" with-editor @delete="onDeleted(attachs,index)"
                      @insert="insertBbsCode"/>
        </template>
      </el-col>
    </el-row>
    <!--表情弹窗-->
    <emote-dialog @command="insertText"/>

    <el-dialog v-model="dialogShow" append-to-body close-on-click-modal title="上传" width="80%">
      <el-select v-model="position" class="m-2" clearable placeholder="水印位置">
        <el-option :key="WatermarkPosition.tl" :value="WatermarkPosition.tl" label="左上"/>
        <el-option :key="WatermarkPosition.tr" :value="WatermarkPosition.tr" label="右上"/>
        <el-option :key="WatermarkPosition.bl" :value="WatermarkPosition.bl" label="左下"/>
        <el-option :key="WatermarkPosition.br" :value="WatermarkPosition.br" label="右下"/>
        <el-option :key="WatermarkPosition.cn" :value="WatermarkPosition.cn" label="中间"/>
      </el-select>
      <br>
      <br>
      <el-upload
          :http-request="uploadRequest"
          :accept="accept.join(',')"
          drag
          multiple
      >
        <el-icon class="el-icon--upload">
          <upload-filled/>
        </el-icon>
        <div class="el-upload__text">
          拖拽或点击上传文件
        </div>
        <template #tip>
          <nga-collapse title="Tips">
            <ul>
              <li>仅支持上传如下后缀的附件:<span v-for="i in accept" style="margin-right: 5px">{{ i }}</span></li>
              <li>快捷操作1：你可以将图片放入剪贴板后(比如各种截图工具)，粘贴到正文框里，图片将会被上传并自动添加原图到当前光标位置</li>
              <li>
                快捷操作2：你可以在资源管理器里选中多个文件并复制之后，粘贴到正文框里，附件将按顺序上传并添加对应代码到当前光标位置；注意如果你使用Ctrl或Shift选中多个文件，上传顺序将与你选中顺序相反，全选则相同。
              </li>
              <li>两种快捷操作均不会添加水印</li>
              <li>本UI将把文件名符合一定规则的图片识别为来自特定网站，并自动添加来源信息：
                <ul>
                  <li>XXXXX_pXX：来自Pixiv</li>
                  <li>连续19位数字：来自Twitter</li>
                </ul>
              </li>
            </ul>
          </nga-collapse>
        </template>
      </el-upload>
    </el-dialog>
  </div>
</template>

<style scoped>
#post-form {
  min-height: 100px;
}

footer {
  margin-top: 10px;
  text-align: center;
}

.post-dropdown {
  margin-right: 3px;
}


</style>